//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <libpub.h>

//==========================================================================

char Bo_GetChar()
{
    char c = 0;
    while(Xo_SerialInputByte(&c));

    return c;
}

char Bo_GetCharEx(int ms)
{
    char c = 0;
    TIMEOUT_INIT(ms);
    while(Xo_SerialInputByte(&c)) {
        if (ms && TIMEOUT_FOUNDED()) {
            break;
        }
    }
    return c;
}

void Bo_PutString(const char *s)
{
    while(*s != 0) {
        Xo_SerialOutputByte(*s++);
    }
}

int Bo_GetString(char *s, int len)
{
    char c;
    int i;
    int maxRead = len - 1;

    for(i = 0; i < maxRead;) {
        /* try to get a byte from the serial port */
        c = Bo_GetChar();

        if((c == '\r') || (c == '\n')) {
            s[i++] = '\0';
            printf("\n");
            return 0;
        }
        else if(c == '\b') { /* FIXME: is this backspace? */
            if (i > 0) {
                i--;printf("\b \b");/* cursor one position back. */
            }
        }
        else {
            s[i++] = c;
            Xo_SerialOutputByte(c);/* echo */
        }
    }

    return -1;
}

//==========================================================================
char *Bo_TrimStringEx(char *s, char c)
{
    while(*s == ' ' || *s == '\r' || *s == '\n' || *s == '&' || *s == c) s++;
    return s;
}

char * Bo_ParseStringEx(char *s, char **sub, char c)
{
    char *p = s;
    while(*p) {
        if (*p == ' ' || *p == c) {
            *p++ = '\0';break;
        }
        p++;
    }

    p = Bo_TrimStringEx(p, c);
    *sub = s;
    return p;
}

unsigned long  Bo_ConvertStringEx(char *s, int mul)
{
    unsigned long l = 0;
    char c;

    while (*s == '0' || *s == 'x' || *s == 'X') s++;//skip [0x]

    while (c = *s++) {
        register int d;

        if (('0' <= c) && (c <= '9'))
            d = c - '0';
        else if (('a' <= c) && (c <= 'f'))
            d = c - 'a' + 10;
        else if (('A' <= c) && (c <= 'F'))
            d = c - 'A' + 10;
        else if ('m' == c || 'M' == c) {
            l = l << 20;continue;
        }
        else if ('k' == c || 'K' == c) {
            l = l << 10;continue;
        }
        else
            break;

        l = (l * mul) + d;
    }
    return l;
}

char * Bo_ParseIntegerEx(char *s, unsigned long *sub, int mul, char c)
{
    char *v;
    s = Bo_ParseStringEx(s, &v, c);
    *sub = Bo_ConvertStringEx(v, mul);
    return s;
}

char *Bo_TrimString(char *s)
{
    return Bo_TrimStringEx(s, ' ');
}

char * Bo_ParseString(char *s, char **sub)
{
    return Bo_ParseStringEx(s, sub, ' ');
}

unsigned long  Bo_ConvertString(char *s)
{
    if (*s == '.') return Bo_ConvertStringEx(++s, 10);
    return Bo_ConvertStringEx(s, 16);//Default is hex
}

char * Bo_ParseInteger(char *s, unsigned long *sub)
{
    char *v;
    s = Bo_ParseString(s, &v);
    *sub = Bo_ConvertString(v);
    return s;
}

int Bo_MatchString(const char *s, const char *sub)
{
    char *p = (char *)s;

    for(;*p && *sub;p++,sub++) {
        if (*p != *sub) return -1;
    }

    if (*sub == '\0') {
        if (*p == '\0' || *p == ' ') return 0;//equal
        else if (p - s >= 3) return 1;//short
    }

    return -1;
}

//==========================================================================
int Bo_GetCommand(char *cmd, int len)
{
    return Bo_GetString(cmd, len);
}

int Bo_ExeCommand(tCommandTbl *pCmdTbl, char *cmd)
{
    TOUT(1, 1, printf("============ExeCommand [%s]\n", cmd));
    if (!pCmdTbl) pCmdTbl = Do_MainCmdTbl;

    char buf[256];
    strncpy(buf, cmd, sizeof(buf));
    cmd = buf;

    char *name;
    cmd = Bo_ParseString(cmd, &name);
    if (!*name) return 1;

    while(pCmdTbl->cmd) {
        if (0 <= Bo_MatchString(pCmdTbl->usage, name)) {
            int ret = pCmdTbl->cmd(cmd);
            TOUT(0, 1, printf("=============return %x\n", ret));
            return ret;
        }
        pCmdTbl++;
    };

    printf("Unknown Command.\n");
    return -1;
}

int _Bo_Alias(char **str)
{
    char buf[256];//temp
    strncpy(buf, *str, sizeof(buf));
    char *cmd = buf;

    char *name;
    cmd = Bo_ParseString(cmd, &name);
    if (!*name) return 1;//no name

    tAliasTbl *pTbl = Do_AliasTbl;
    while(*pTbl->alias) {
        if (0 <= Bo_MatchString(pTbl->alias, name)) {
            break;
        }
        pTbl++;
    }

    if (!*pTbl->alias) return 1;//not found

#define MAXPARAMNUM 10
    char *param[MAXPARAMNUM];
    int i = 0,j = 0;
    while(*cmd && i < MAXPARAMNUM) {
        cmd = Bo_ParseString(cmd, &param[i++]);
    }

    char *src = pTbl->cmd;
    char *dst = *str;
    while(*src) {
        if (*src == '$') {
            if (src[1] == '*') {
                for(j = 0; j < i; j++) {
                    char *p = param[j];
                    while(*p) *dst++ = *p++;//replace all
                    *dst++ = ' ';
                }
            }
            else {
                j = src[1] - '1';
                if (j >= 0 && j < i) {
                    char *p = param[j];
                    while(*p) *dst++ = *p++;//replace
                }
            }
            src += 2;//skip '$'
        }
        else
            *dst++ = *src++;
    }
    *dst = 0;

    TOUT(1, 1, printf("Got Alias [%s]\n", *str));
    return 0;
}

void Bo_BatchCommands(char *cmds)
{
    char buf[1024];
    strncpy(buf, cmds, sizeof(buf));
    cmds = buf;

    if (Do_AliasTbl) _Bo_Alias(&cmds);

    char *p = cmds;
    char *cmd = p;
    do {
        if (*p == '\0' || *p == '&' || *p == '\r' || *p == '\n') {
            if (*p) *p++ = '\0';

            uLastError = Bo_ExeCommand(0, Bo_TrimString(cmd));
            cmd = p;//next
        }
    }while(*p++);

    return ;
}


void Bo_ShowMenu(tMenuTbl *pMenuTbl, tCommandTbl *pCmdTbl, int flags)
{
    do {
        tMenuTbl *p = pMenuTbl;
        while(*p->item) {
            printk("<%c>\t\t%s\t%s\n", p->hotkey, p->item, p->cmd);
            p++;
        }
        printk("[q]\t\tQuit.\n");

        printk("Select:");
        char c = Bo_GetChar();
        Xo_SerialOutputByte(c);/* echo */printk("\n");
        if (c == 'q' || c == 'Q') break;

        p = pMenuTbl;
        while(*p->item) {
            if (c == p->hotkey) {
                Bo_ExeCommand(pCmdTbl, p->cmd);
                break;
            }
            p++;
        }
        if (!*p->item) {
            printk("Input Wrong!\n");
        }
    }while(flags);

    return ;
}

int Bo_Print(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);

    char buf[1024];
    uint_t uLength = _vsprintf(buf, fmt, ap);

    va_end(ap);

    Bo_PutString(buf);

    return uLength;
}

